<?php

namespace app\extra\WeixinSDK;

use app\extra\WeixinSDK\V3\JsApipub;

class WxPayHelper {

    /**
     * 配置参数
     * 
     * @var array 
     */
    protected $_config = array();
    var $parameters; //cft 参数

    function __construct() {
        $this->_config = array(
            'APPID' => WxConfig::APPID,
            'APPKEY' => WxConfig::APPKEY,
            'SIGNTYPE' => WxConfig::SIGNTYPE,
            'PARTNERKEY' => WxConfig::PARTNERKEY,
            'APPSERCERT' => WxConfig::APPSERCERT,
            'PARTNERID' => WxConfig::PARTNERID,
            'CALLBACKURL' => WxConfig::CALLBACKURL,
            'input_charset' => WxConfig::input_charset,
        );
    }

    function setParameter($parameter, $parameterValue) {
        $commonUtil = new CommonUtil();
        $this->parameters[$commonUtil->trimString($parameter)] = $commonUtil->trimString($parameterValue);
    }

    function getParameter($parameter) {
        return $this->parameters[$parameter];
    }

    protected function create_noncestr($length = 16) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str.= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
            //$str .= $chars[ mt_rand(0, strlen($chars) - 1) ];  
        }

        return $str;
    }

    function check_cft_parameters() {
        if ($this->parameters["bank_type"] == null || $this->parameters["body"] == null || $this->parameters["partner"] == null ||
                $this->parameters["out_trade_no"] == null || $this->parameters["total_fee"] == null || $this->parameters["fee_type"] == null ||
                $this->parameters["notify_url"] == null || $this->parameters["spbill_create_ip"] == null || $this->parameters["input_charset"] == null
        ) {
            return false;
        }
        return true;
    }

    protected function get_cft_package() {
        try {

            if (null == $this->_config['PARTNERKEY'] || "" == $this->_config['PARTNERKEY']) {
                throw new SDKRuntimeException("密钥不能为空！" . "<br>");
            }
            $commonUtil = new CommonUtil();
            ksort($this->parameters);
            $unSignParaString = $commonUtil->formatQueryParaMap($this->parameters, false);

            $paraString = $commonUtil->formatQueryParaMap($this->parameters, true);

            $md5SignUtil = new MD5SignUtil();

            return $paraString . "&sign=" . $md5SignUtil->sign($unSignParaString, $commonUtil->trimString($this->_config['PARTNERKEY']));
        } catch (SDKRuntimeException $e) {
            die($e->errorMessage());
        }
    }

    protected function get_biz_sign($bizObj) {
        foreach ($bizObj as $k => $v) {
            $bizParameters[strtolower($k)] = $v;
        }

        try {
            if ($this->_config['APPKEY'] == "") {
                throw new SDKRuntimeException("APPKEY为空！" . "<br>");
            }
            $bizParameters["appkey"] = $this->_config['APPKEY'];
            ksort($bizParameters);
            //var_dump($bizParameters);
            $commonUtil = new CommonUtil();

            $bizString = $commonUtil->formatBizQueryParaMap($bizParameters, false);

            //$bizString = strtolower($bizString);
            //var_dump($bizString);
            return sha1($bizString);
        } catch (SDKRuntimeException $e) {
            die($e->errorMessage());
        }
    }

    //生成app支付请求json
    /*
      {
      "appid":"wwwwb4f85f3a797777",
      "traceid":"crestxu",
      "noncestr":"111112222233333",
      "package":"bank_type=WX&body=XXX&fee_type=1&input_charset=GBK&notify_url=http%3a%2f%2f
      www.qq.com&out_trade_no=16642817866003386000&partner=1900000109&spbill_create_ip=127.0.0.1&total_fee=1&sign=BEEF37AD19575D92E191C1E4B1474CA9",
      "timestamp":1381405298,
      "app_signature":"53cca9d47b883bd4a5c85a9300df3da0cb48565c",
      "sign_method":"sha1"
      }
     */
    function create_app_package($traceid = "") {
        //echo $this->create_noncestr();
        try {

            if ($this->check_cft_parameters() == false) {
                throw new SDKRuntimeException("生成package参数缺失！" . "<br>");
            }
            $nativeObj["appid"] = $this->_config['APPID'];
            $nativeObj["traceid"] = $traceid;
            $nativeObj["noncestr"] = $this->create_noncestr(32);
            $nativeObj["package"] = $this->get_cft_package();
            $nativeObj["timestamp"] = time();
            $nativeObj["app_signature"] = $this->get_biz_sign($nativeObj);
            $nativeObj["sign_method"] = $this->_config['SIGNTYPE'];

            return json_encode($nativeObj);
        } catch (SDKRuntimeException $e) {
            die($e->errorMessage());
        }
    }

    function get_sign($post) {

        $commonUtil = new CommonUtil();
        $nativeObj["appid"] = $this->_config['APPID'];
        $nativeObj["appkey"] = $this->_config['APPKEY'];
        $nativeObj["noncestr"] = $post['noncestr'];
        $nativeObj["package"] = 'Sign=' . $post["package"];
        $nativeObj["partnerid"] = $this->_config['PARTNERID'];
        $nativeObj["prepayid"] = $post["prepayid"];
        $nativeObj["timestamp"] = $post['timestamp'];

        $bizString = $this->get_biz_sign($nativeObj);
        return $bizString;
    }

    public function get_ios_sign($post) {
        $nativeObj["appid"] = $this->_config['APPID'];
        $nativeObj["appkey"] = $this->_config['APPKEY'];
        $nativeObj["noncestr"] = $post['noncestr'];
        $nativeObj["package"] = 'Sign=WXPay';
        $nativeObj["partnerid"] = $this->_config['PARTNERID'];
        $nativeObj["prepayid"] = $post["prepayid"];
        $nativeObj["timestamp"] = $post['timestamp'];

        $bizString = $this->get_biz_sign($nativeObj);
        return $bizString;
    }

    //生成jsapi支付请求json
    /*
      "appId" : "wxf8b4f85f3a794e77", //公众号名称，由商户传入
      "timeStamp" : "189026618", //时间戳这里随意使用了一个值
      "nonceStr" : "adssdasssd13d", //随机串
      "package" : "bank_type=WX&body=XXX&fee_type=1&input_charset=GBK&notify_url=http%3a%2f
      %2fwww.qq.com&out_trade_no=16642817866003386000&partner=1900000109&spbill_create_i
      p=127.0.0.1&total_fee=1&sign=BEEF37AD19575D92E191C1E4B1474CA9",
      //扩展字段，由商户传入
      "signType" : "SHA1", //微信签名方式:sha1
      "paySign" : "7717231c335a05165b1874658306fa431fe9a0de" //微信签名
     */
    function create_biz_package() {
        try {

            if ($this->check_cft_parameters() == false) {
                throw new SDKRuntimeException("<script>alert('支付失败');</script>");
            }
            $nativeObj["appId"] = $this->_config['APPID'];
            $nativeObj["package"] = $this->get_cft_package();
            $nativeObj["timeStamp"] = strval(time());
            $nativeObj["nonceStr"] = $this->create_noncestr();
            $nativeObj["paySign"] = $this->get_biz_sign($nativeObj);
            $nativeObj["signType"] = $this->_config['SIGNTYPE'];

            return json_encode($nativeObj);
        } catch (SDKRuntimeException $e) {
            die($e->errorMessage());
        }
    }

    //生成原生支付url
    /*
      weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXXX&productid=XXXXXX&timestamp=XXXXXX&noncestr=XXXXXX
     */
    function create_native_url($productid) {

        $commonUtil = new CommonUtil();
        $nativeObj["appid"] = $this->_config['APPID'];
        $nativeObj["productid"] = urlencode($productid);
        $nativeObj["timestamp"] = time();
        $nativeObj["noncestr"] = $this->create_noncestr();
        $nativeObj["sign"] = $this->get_biz_sign($nativeObj);
        $bizString = $commonUtil->formatBizQueryParaMap($nativeObj, false);
        return "weixin://wxpay/bizpayurl?" . $bizString;
    }

    //生成原生支付请求xml
    /*
      <xml>
      <AppId><![CDATA[wwwwb4f85f3a797777]]></AppId>
      <Package><![CDATA[a=1&url=http%3A%2F%2Fwww.qq.com]]></Package>
      <TimeStamp> 1369745073</TimeStamp>
      <NonceStr><![CDATA[iuytxA0cH6PyTAVISB28]]></NonceStr>
      <RetCode>0</RetCode>
      <RetErrMsg><![CDATA[ok]]></ RetErrMsg>
      <AppSignature><![CDATA[53cca9d47b883bd4a5c85a9300df3da0cb48565c]]>
      </AppSignature>
      <SignMethod><![CDATA[sha1]]></ SignMethod >
      </xml>
     */
    function create_native_package($retcode = 0, $reterrmsg = "ok") {
        try {
            if ($this->check_cft_parameters() == false && $retcode == 0) {   //如果是正常的返回， 检查财付通的参数
                throw new SDKRuntimeException("生成package参数缺失！" . "<br>");
            }
            $nativeObj["AppId"] = $this->_config['APPID'];
            $nativeObj["Package"] = $this->get_cft_package();
            $nativeObj["TimeStamp"] = time();
            $nativeObj["NonceStr"] = $this->create_noncestr();
            $nativeObj["RetCode"] = $retcode;
            $nativeObj["RetErrMsg"] = $reterrmsg;
            $nativeObj["AppSignature"] = $this->get_biz_sign($nativeObj);
            $nativeObj["SignMethod"] = $this->_config['SIGNTYPE'];
            $commonUtil = new CommonUtil();

            return $commonUtil->arrayToXml($nativeObj);
        } catch (SDKRuntimeException $e) {
            die($e->errorMessage());
        }
    }

    /**
     * 微信支付回调数据的验证
     * 
     * by smy
     */
    function dataverify($get) {
        //验证sign
        $commonUtil = new CommonUtil();

        //商户号
        if (!isset($get['partner']) || empty($get['partner']) || $get['partner'] != $this->_config['PARTNERID']) {
            // \Our\Log::getInstance()->write('微信支付回调，partner数据有误。回调数据：' . var_export($get, true), 'WXpayerror.log');
            return false;
        }
        //支付状态
        if (!isset($get['trade_state']) || $get['trade_state'] === 0) {
            // \Our\Log::getInstance()->write('微信支付回调，trade_state数据有误。回调数据：' . var_export($get, true), 'WXpayerror.log');
            return false;
        }
        //支付状态
        if (!isset($get['sign']) || empty($get['sign'])) {
            //  \Our\Log::getInstance()->write('微信支付回调，sign数据有误。回调数据：' . var_export($get, true), 'WXpayerror.log');
            return false;
        }

        $string1 = $commonUtil->formatQueryParaMap($get, false);

        $md5singutil = new MD5SignUtil();
        $verifySignature = $md5singutil->verifySignature($string1, $get['sign'], $this->_config['PARTNERKEY']);
        if ($verifySignature === false) {
            // \Our\Log::getInstance()->write('微信支付回调，sign数据有误。回调数据：' . var_export($get, true), 'WXpayerror.log');
            return false;
        }

        return $get;
    }

    /**
     * 微信发货
     *
     * by smy
     */
    function deliver($data) {
        if (!empty($data)) {
            //获取 access_token 
            $appid = $this->_config['APPID'];
            $secret = $this->_config['APPSERCERT'];
            //$ch = curl_init("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$secret."");//初始化curl
            //weixin.pba.cn共用access_token,从weixin.pba.cn共用
            $access_token = file_get_contents("http://weixin.pba.cn/api/getaccesstoken?appid=" . $appid . "&secret=" . $secret);
            $url = "https://api.weixin.qq.com/pay/delivernotify?access_token=" . $access_token;

            $post = array(
                "appid" => $appid,
                "openid" => $data['openid'],
                "transid" => $data['transaction_id'],
                "out_trade_no" => $data['order_id'],
                "deliver_timestamp" => time(),
                "deliver_status" => $data['status'],
                "deliver_msg" => $data['msg'],
            );
            $sign = $this->get_biz_sign($post);
            $post['app_signature'] = $sign;
            $post['sign_method'] = 'sha1';
            $ch2 = curl_init(); //初始化curl
            $curlPost = json_encode($post);

            curl_setopt($ch2, CURLOPT_URL, $url);
            curl_setopt($ch2, CURLOPT_HEADER, 0); //设置header
            curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上
            curl_setopt($ch2, CURLOPT_POST, 1); //post提交方式

            curl_setopt($ch2, CURLOPT_POSTFIELDS, $curlPost);
            $data2 = curl_exec($ch2); //运行curl 
            curl_close($ch2);
            return $data2;
        }

        return false;
    }

    /**
     * 微信付款成功发信息
     *
     * by smy
     */
    public function paysendmsg($post) {
        if (!empty($post)) {
            $post2 = array(
                'touser' => $post['OpenId'],
                'template_id' => 'e5hW4c_jAXT3S9bRU7itS8pmNvHZ6fqADXnwrma5oU8',
                'url' => '',
                'data' => array(
                    'first' => array('value' => "我们已收到您的订单" . $post['order_sn'] . "的货款，开始为您打包商品，请耐心等待: )"),
                    'orderMoneySum' => array('value' => $post['money_paid'] . "元"),
                    'orderProductName' => array('value' => $post['goods_name'] . "等"),
                    'orderpre' => array('value' => '　'),
                    'Remark' => array('value' => "如有问题请致电400-7796-400或直接在微信输入“人工客服”，P妞将第一时间为您服务！"),
                )
            );
            //获取 access_token
            $appid = $this->_config['APPID'];
            $secret = $this->_config['APPSERCERT'];
            //weixin.pba.cn共用access_token,从weixin.pba.cn共用
            $access_token = file_get_contents("http://weixin.pba.cn/api/getaccesstoken?appid=" . $appid . "&secret=" . $secret);
            $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" . $access_token;

            $ch2 = curl_init(); //初始化curl
            $curlPost = json_encode($post2);

            curl_setopt($ch2, CURLOPT_URL, $url);
            curl_setopt($ch2, CURLOPT_HEADER, 0); //设置header
            curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上
            curl_setopt($ch2, CURLOPT_POST, 1); //post提交方式

            curl_setopt($ch2, CURLOPT_POSTFIELDS, $curlPost);
            $data2 = curl_exec($ch2); //运行curl
            curl_close($ch2);
            return $data2;
        }

        return false;
    }

    /**
     *  获取CODE 在微信内核
     *
     */
    function getcodewx($backurl) {

        $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . $this->_config['APPID'] .
                "&redirect_uri=" . $backurl . "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
        header('Location: ' . $url);
        exit;
    }

    /**
     * 微信获得地址
     * @param unknown $url 当前url
     * @param string $appid
     * @param string $appsercert
     * @return mixed
     */
    public function getaddress($url, $appid, $appsercert, $code) {
        //获取accesstoken
        $url2 = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $appid . '&secret=' . $appsercert . "&code=" . $code . "&grant_type=authorization_code";
        $tokenres = $this->curlpost($url2, '', 'GET');
        $tk = json_decode($tokenres, true);
        if (!isset($tk['access_token'])) {
            return false;
        }
        //签名参数
        $signstr['appid'] = $appid;
        $signstr['url'] = $url;
        $signstr['timestamp'] = time();
        $signstr['noncestr'] = time();
        $signstr['accesstoken'] = $tk['access_token'];
        $commonUtil = new CommonUtil();
        $signstrbiz = $commonUtil->formatBizQueryParaMap($signstr, false);
        //签名加密    	 
        $addrSign = sha1($signstrbiz);
        $data['appId'] = $appid;
        $data['scope'] = "jsapi_address";
        $data['signType'] = "sha1";
        $data['addrSign'] = $addrSign;
        $data['timeStamp'] = $signstr['timestamp'];
        $data['nonceStr'] = $signstr['noncestr'];
        unset($signstr);
        return $data;
    }

    /**
     * 生成支付请求json
     * @param unknown $url 当前url
     * @param string $appid
     * @param string $appsercert
     * @return mixed
     */
    public function requestjson($post, $type = 'app') {
        $wxPayHelper = new \WeixinSDK\WxJsPayHelper();
        $wxPayHelper->setParameter("bank_type", "WX");
        $wxPayHelper->setParameter("body", $post['body']);
        $wxPayHelper->setParameter("partner", WxConfig::PARTNERID);
        $wxPayHelper->setParameter("out_trade_no", $post['out_trade_no']);
        $wxPayHelper->setParameter("total_fee", $post['totalFee'] * 100);
        $wxPayHelper->setParameter("fee_type", 1);
        $wxPayHelper->setParameter("notify_url", WxConfig::CALLBACKURL);
        $wxPayHelper->setParameter("spbill_create_ip", \Our\Common::getClientIp());
        $wxPayHelper->setParameter("input_charset", WxConfig::input_charset);
        if ($type == 'jsapi') {
            $curlPost = $wxPayHelper->create_biz_package();
        } else {
            $curlPost = $wxPayHelper->create_app_package($post['traceid']);
        }

        return $curlPost;
    }

    /**
     * 生成js支付请求
     * @param unknown $url 当前url
     * @param string $appid
     * @param string $appsercert
     * @return mixed
     */
    public function jssendpayment($post, $type = 'app') {
        if (!isset($post['out_trade_no'])) {
            exception('微信支付，数据有误,请求参数：' . var_export($post, true), 1000111);
        }

        //默认显示旧的预售界面
        if (!isset($post['backurl'])) {
            exception('微信支付，数据有误,请求参数：' . var_export($post, true), 1000111);
        }
        $backurl = base64_decode($post['backurl']);
        if (isset($post['backurl']) && $post['backurl']) {
            setcookie('weixinpaybackurl', $post['backurl']); //由于微信授权获取code回调后会过滤掉带&的参数,因此将回调地址保存在cookie中
        }
        //请求订单信息
        try {
            $payment = new \app\common\business\finance\Payment();
            $data = $payment->getrequest($post['out_trade_no'], 2);
            $data['errno'] = 200;
            $data['errmsg'] = 0;
        } catch (Exception $e) {
            if (!($e->getCode() > 100000)) {
                throw $e;
            }
            $data['errno'] = $e->getCode();
            $data['errmsg'] = $e->getMessage();
            return array("view" => "jssendpayment", "errno" => $data['errno'], "errmsg" => $data['errmsg'], 'backurl' => $backurl);
        }
        $Posts = $post;
        $post = array_merge($post, $data);
        //不在微信内核访问显示二维码
        $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
      /*  if (strpos($user_agent, 'MicroMessenger') === false || (isset($_REQUEST['showcode']) && $_REQUEST['showcode'] == 'show')) {

            $Posts['order_amount'] = $post['totalFee'] * 100;
            $Posts['out_trade_no'] = "w" . $post['out_trade_no'];
            $JsApipub = new JsApipub();
            $value = $JsApipub->codenative($Posts);
            $qrcode = new \app\extra\WeixinSDK\Qrcode();
            $errorCorrectionLevel = "L";
            $matrixPointSize = "5";

            $img = $qrcode->png($value, false, $errorCorrectionLevel, $matrixPointSize);
            return array("view" => "jssendpaymentqrcode", 'img' => $img);
        }
*/
        $wxPayHelper = new \app\extra\WeixinSDK\V3\WxPayPubHelper();
        $post['order_amount'] = $post['totalFee'] * 100;
        $curlPost = $wxPayHelper->requestpayjsapi($post); 
        return array("view" => "jssendpayment", "errno" => $data['errno'], "errmsg" => $data['errmsg'], "url" => $curlPost,  "dataurl" => json_decode($curlPost,true),'out_trade_no' => $post['out_trade_no'], 'backurl' => base64_decode($_COOKIE['weixinpaybackurl']), 'enbackurl' => $post['backurl'], 'order_amount' => $post['totalFee'], 'old_out_trade_no' => $Posts['out_trade_no']);
    }

    /**
     * 支付订单回调 处理
     *
     */
    public function _ordercallback($post) {

        $post['log_content'] = json_encode($post);
        $totalFee = $post['total_fee'];
        $post['total_fee'] = round($post['total_fee'] / 100, 2);
        $orderId = $post['out_trade_no'];

        //支付成功向微信推送信息
        if (isset($post['OpenId'])) {
            //请求订单信息 
//            $wxPayHelper = new WxJsPayHelper();
//            $post2['order_id'] = $post['out_trade_no'];
//            $post2['mobile'] = "";
//            $post2['OpenId'] = $post['OpenId'];
//            $post2['order_sn'] = $post['out_trade_no'];
//            $post2['money_paid'] = $totalFee;
//            $post2['goods_name'] = 'dd';
//            $this->paysendmsg($post2);
        }
        if (isset($post['time_end'])) {
            $post['pay_time'] = strtotime($post['time_end']);
        }
        $paymentObj = new \app\common\business\finance\Payment();
        //订单状态修改 支付订单 
        return $paymentObj->paycallback($post);
    }

    function curlpost($url, $post = '', $type = 'POST') {
        $ch = curl_init(); //初始化curl
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0); //设置header
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);

        if ($type == 'POST') {
            curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        }

        $data = curl_exec($ch); //运行curl
        curl_close($ch);
        return $data;
    }

}

?>